package br.com.hstar.server.quarto;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;

import br.com.hstar.client.formapgto.FormaPgtoUI;
import br.com.hstar.client.produto.produto.ProdutoUI;
import br.com.hstar.client.quarto.QuartoService;
import br.com.hstar.client.quarto.QuartoUI;
import br.com.hstar.model.formapgto.FormaPgtoDO;
import br.com.hstar.model.produto.ProdutoDO;
import br.com.hstar.model.quarto.QuartoDO;
import br.com.hstar.server.DozerHelper;
import br.com.hstar.server.DozerUtility;
import br.com.hstar.server.HibernateUtility;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class QuartoServiceImpl extends RemoteServiceServlet implements QuartoService {

	/**
	 * 
	 */
	private static final long serialVersionUID = 336380964753920657L;


	//este método salva ou atualiza o quarto, dependendo do paramatro "isSave" passado.
	public void saveOrUpdate(QuartoUI objUI, boolean isSave) {
		
		//mapeia a lista de produtos do objUI, de UI para DO
		List produtosDOList = mapToProdutoDOList(objUI.getProdutosConsumidos());
		List formaPgtoDOList = mapToFormaPgtoDOList(objUI.getFormaspgto());
		
		//remove a lista de produtosUI e FOrmaPgtoUI do objUI para nao dar erro no Dozer
		if(objUI.getProdutosConsumidos() != null) objUI.setProdutosConsumidos(null);
		if(objUI.getFormaspgto() != null) objUI.setProdutosConsumidos(null);
		
		//faz o mapeamento
		QuartoDO objDO = (QuartoDO) DozerUtility.getMapper().map(objUI, QuartoDO.class);
		
		//reinsere a lista, agora no DO
		if(produtosDOList != null && produtosDOList.size() > 0) objDO.setProdutosConsumidos(produtosDOList);
		if(formaPgtoDOList != null && formaPgtoDOList.size() > 0) objDO.setFormaspgto(formaPgtoDOList);
		
		//Verifica se o quarto está sendo fechado
		if(objDO.getSituacao().equals(new Integer(1)) && !objDO.getHoraSaida().equals(""))
		{
			//debita os produtos
			for (Iterator iterator = objDO.getProdutosConsumidos().iterator(); iterator.hasNext();) {
				ProdutoDO produto = (ProdutoDO) iterator.next();
				debitar(produto.getId(), 1);				
			}
		}

		//se ja existe o quarto no estado de sujo ou ocupado
		//devemos apenas atualizar. Caso contrário, devemos salvar
		if(existeQuarto(objUI.getNumero())) {
			Session sessao = HibernateUtility.getSession();
			Transaction transaction = sessao.beginTransaction();
			sessao.update(objDO);
			transaction.commit();
			sessao.close();
		} else {
			Session sessao = HibernateUtility.getSession();
			Transaction transaction = sessao.beginTransaction();
			sessao.save(objDO);
			transaction.commit();
			sessao.close();
		}
		
	}
	
	public List listAll() {
		Session sessao = HibernateUtility.getSession();
		Criteria select = sessao.createCriteria(QuartoDO.class);
		ArrayList objetos = (ArrayList)select.list();
		sessao.close();
		
		return DozerHelper.mapList(DozerUtility.getMapper(), objetos, QuartoUI.class);
	}
	
	public QuartoUI retrieveById(Long id) {
		Session sessao = HibernateUtility.getSession();
		Criteria cri = sessao.createCriteria(QuartoDO.class);
		cri.add(Restrictions.eq("id", id));
		QuartoDO objDO = (QuartoDO) cri.uniqueResult();
		sessao.close();
				
		QuartoUI objUI = (QuartoUI) DozerUtility.getMapper().map(objDO, QuartoUI.class);
		
	  	return objUI;
	}
	
	public void delete(Long id) {
		Session sessao = HibernateUtility.getSession();
		Transaction transaction = sessao.beginTransaction();

		Criteria cri = sessao.createCriteria(QuartoDO.class);
		cri.add(Restrictions.eq("id", id));
		QuartoDO objDO = (QuartoDO) cri.uniqueResult();
		sessao.delete(objDO);

		transaction.commit();
		sessao.close();
	}
	
	
	//retorna o quarto, caso ele esteja sujo, ou ocupado, pois
	//ele so devcera ser carregado, nessas duas condicoes, cvaso
	//contrario, deve-se criar um novo quarto para ser persistido
	public QuartoUI retrieveQuartoUsavel(Integer numero) {
		QuartoUI objUI = null;
		
		Session sessao = HibernateUtility.getSession();
		Criteria cri = sessao.createCriteria(QuartoDO.class);
		//pega os quartos diferente de "vazio"
		cri.add(Restrictions.ne("situacao", new Integer(0)));
		cri.add(Restrictions.eq("numero", numero));
		QuartoDO objDO = (QuartoDO) cri.uniqueResult();
		sessao.close();
		
		//mapeia a lista de formas de pgto
		List auxUI = new ArrayList();
		List auxProd = new ArrayList();
		if(objDO != null) {
			List forms = objDO.getFormaspgto();
			for(int i = 0; i<forms.size(); i++){;
				FormaPgtoUI fUI = (FormaPgtoUI)DozerUtility.getMapper().
						map((FormaPgtoDO)forms.get(i), FormaPgtoUI.class);
				auxProd.add(fUI);
			}
			
			//anula a lista de formas de pgto
			objDO.setFormaspgto(null);
				
			//mapeia os produtos consumidos na mao, pois o dozer n ta fazendo
			
			List prods = objDO.getProdutosConsumidos();
			for (int i = 0; i < prods.size(); i++) {
				ProdutoDO p = (ProdutoDO)prods.get(i);
				ProdutoUI pUI = (ProdutoUI)DozerUtility.getMapper().map(p, ProdutoUI.class);
				auxUI.add(pUI);
			}
			//anula a lista de produtos
			objDO.setProdutosConsumidos(null);
			
			objUI = (QuartoUI) DozerUtility.getMapper().map(objDO, QuartoUI.class);
			
			//seta novamente a lista de produtos e de formas de pgto já mapeada
			objUI.setProdutosConsumidos(auxUI);
			objUI.setFormaspgto(auxProd);
		}

		return objUI;
	}
	
	
	//metodo que mapeia a lsita de produtos, transformando de DO pra UI
	//pois o dozer nao esta fazendo isso automaticamente
	private List mapToProdutoDOList(List produtosUI) {
		List auxDO = new ArrayList();
		for (int i = 0; i < produtosUI.size(); i++) {
			ProdutoUI pUI = (ProdutoUI)produtosUI.get(i);
			auxDO.add((ProdutoDO) DozerUtility.getMapper().map(pUI, ProdutoDO.class));
		}
		
		return auxDO;
	}
	
	private List mapToFormaPgtoDOList(List formaPgtoUI) {
		List auxDO = new ArrayList();
		for (int i = 0; i < formaPgtoUI.size(); i++) {
			FormaPgtoUI pUI = (FormaPgtoUI)formaPgtoUI.get(i);
			auxDO.add((FormaPgtoDO) DozerUtility.getMapper().map(pUI, FormaPgtoDO.class));
		}
		
		return auxDO;
	}
	
	
	//workaround para verificar se um quarto ja esta cadastrado no estado
	//diferente de vazio, ou seja, sujo ou ocupado.
	private boolean existeQuarto(Integer numero) {
		Session sessao = HibernateUtility.getSession();	
		
		Criteria cri = sessao.createCriteria(QuartoDO.class);
		
		//pega os quartos diferente de "vazio"
		cri.add(Restrictions.ne("situacao", new Integer(0)));
		cri.add(Restrictions.eq("numero", numero));
		
		QuartoDO aux = (QuartoDO) cri.uniqueResult();

		sessao.close();
		
		return (aux != null);
	}
	
	private void debitar(Long id, int quantidade)
	{
		Session sessao = HibernateUtility.getSession();
		Criteria cri = sessao.createCriteria(ProdutoDO.class);
		cri.add(Restrictions.eq("id", id));
		
		ProdutoDO prodDO = (ProdutoDO) cri.uniqueResult();
		
		prodDO.setQuantidadeConsumo(prodDO.getQuantidadeConsumo()-quantidade);
		
		sessao.update(prodDO);				
	}
}
